﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Threading;
namespace TA.DotNetUtils
{
	[Serializable, DebuggerDisplay("Count = {Count}")]
	public class VList<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
	{
		#region PUBLIC
		#region INIT
		public VList()
		{
			this._items = VList<T>._emptyArray;
		}
		public VList(IEnumerable<T> collection)
		{
			if (collection == null)
			{
				throw new ArgumentNullException("collection");
			}
			ICollection<T> is2 = collection as ICollection<T>;
			if (is2 != null)
			{
				int count = is2.Count;
				this._items = new T[count];
				is2.CopyTo(this._items, 0);
				this._size = count;
			}
			else
			{
				this._size = 0;
				this._items = new T[4];
				using (IEnumerator<T> enumerator = collection.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						this.Add(enumerator.Current);
					}
				}
			}
		}
		public VList(int capacity)
		{
			if (capacity < 0)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			this._items = new T[capacity];
		}
		#endregion
		#region METHODS
		public virtual void Add(T item)
		{
			if (this.IsOkToAdd(item))
			{
				if (this._size == this._items.Length)
				{
					this.EnsureCapacity(this._size + 1);
				}
				this._items[this._size++] = item;
				++this._version;
				OnItemAdded(item);
			}
		}
		public virtual void AddRange(IEnumerable<T> collection)
		{
			this.InsertRange(this._size, collection);
		}
		public ReadOnlyCollection<T> AsReadOnly()
		{
			return new ReadOnlyCollection<T>(this);
		}
		public int BinarySearch(T item)
		{
			return this.BinarySearch(0, this.Count, item, null);
		}
		public int BinarySearch(T item, IComparer<T> comparer)
		{
			return this.BinarySearch(0, this.Count, item, comparer);
		}
		public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
		{
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException("index or count");
			}
			if ((this._size - index) < count)
			{
				throw new ArgumentException("Size, index, count");
			}
			return Array.BinarySearch<T>(this._items, index, count, item, comparer);
		}
		public virtual void Clear()
		{
			foreach (T t in this)
				this.OnItemRemoved(t);
			if (this._size > 0)
			{
				Array.Clear(this._items, 0, this._size);
				this._size = 0;
			}
			this._version++;
		}
		public bool Contains(T item)
		{
			if (item == null)
			{
				for (int j = 0; j < this._size; j++)
				{
					if (this._items[j] == null)
					{
						return true;
					}
				}
				return false;
			}
			EqualityComparer<T> comparer = EqualityComparer<T>.Default;
			for (int i = 0; i < this._size; i++)
			{
				if (comparer.Equals(this._items[i], item))
				{
					return true;
				}
			}
			return false;
		}
		public VList<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
		{
			if (converter == null)
			{
				throw new ArgumentNullException("converter");
			}
			VList<TOutput> list = new VList<TOutput>(this._size);
			for (int i = 0; i < this._size; i++)
			{
				list._items[i] = converter(this._items[i]);
			}
			list._size = this._size;
			return list;
		}
		public void CopyTo(T[] array)
		{
			this.CopyTo(array, 0);
		}
		public void CopyTo(T[] array, int arrayIndex)
		{
			Array.Copy(this._items, 0, array, arrayIndex, this._size);
		}
		public void CopyTo(int index, T[] array, int arrayIndex, int count)
		{
			if ((this._size - index) < count)
			{
				throw new ArgumentException("Index, Count");
			}
			Array.Copy(this._items, index, array, arrayIndex, count);
		}
		public bool Exists(Predicate<T> match)
		{
			return (this.FindIndex(match) != -1);
		}
		public T Find(Predicate<T> match)
		{
			if (match == null)
			{
				throw new ArgumentNullException("match");
			}
			for (int i = 0; i < this._size; i++)
			{
				if (match(this._items[i]))
				{
					return this._items[i];
				}
			}
			return default(T);
		}
		public VList<T> FindAll(Predicate<T> match)
		{
			if (match == null)
			{
				throw new ArgumentNullException("match");
			}
			VList<T> list = new VList<T>();
			for (int i = 0; i < this._size; i++)
			{
				if (match(this._items[i]))
				{
					list.Add(this._items[i]);
				}
			}
			return list;
		}
		public int FindIndex(Predicate<T> match)
		{
			return this.FindIndex(0, this._size, match);
		}
		public int FindIndex(int startIndex, Predicate<T> match)
		{
			return this.FindIndex(startIndex, this._size - startIndex, match);
		}
		public int FindIndex(int startIndex, int count, Predicate<T> match)
		{
			if (startIndex > this._size)
			{
				//ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
			}
			if ((count < 0) || (startIndex > (this._size - count)))
			{
				//ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count);
			}
			if (match == null)
			{
				//ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
			}
			int num = startIndex + count;
			for (int i = startIndex; i < num; i++)
			{
				if (match(this._items[i]))
				{
					return i;
				}
			}
			return -1;
		}
		public T FindLast(Predicate<T> match)
		{
			if (match == null)
			{
				throw new ArgumentNullException("match");
			}
			for (int i = this._size - 1; i >= 0; i--)
			{
				if (match(this._items[i]))
				{
					return this._items[i];
				}
			}
			return default(T);
		}
		public int FindLastIndex(Predicate<T> match)
		{
			return this.FindLastIndex(this._size - 1, this._size, match);
		}
		public int FindLastIndex(int startIndex, Predicate<T> match)
		{
			return this.FindLastIndex(startIndex, startIndex + 1, match);
		}
		public int FindLastIndex(int startIndex, int count, Predicate<T> match)
		{
			if (match == null)
			{
				throw new ArgumentNullException("match");
			}
			if (this._size == 0)
			{
				if (startIndex != -1)
				{
					throw new ArgumentOutOfRangeException("startIndex");
				}
			}
			else if (startIndex >= this._size)
			{
				throw new ArgumentOutOfRangeException("startIndex, size");
			}
			if ((count < 0) || (((startIndex - count) + 1) < 0))
			{
				throw new ArgumentOutOfRangeException("startIndex, count");
			}
			int num = startIndex - count;
			for (int i = startIndex; i > num; i--)
			{
				if (match(this._items[i]))
				{
					return i;
				}
			}
			return -1;
		}
		public void ForEach(Action<T> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("match");
			}
			for (int i = 0; i < this._size; i++)
			{
				action(this._items[i]);
			}
		}
		public Enumerator GetEnumerator()
		{
			return new Enumerator((VList<T>)this);
		}
		public VList<T> GetRange(int index, int count)
		{
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException("index or count");
			}
			if ((this._size - index) < count)
			{
				throw new ArgumentOutOfRangeException("index, count");
			}
			VList<T> list = new VList<T>(count);
			Array.Copy(this._items, index, list._items, 0, count);
			list._size = count;
			return list;
		}
		public int IndexOf(T item)
		{
			return Array.IndexOf<T>(this._items, item, 0, this._size);
		}
		public int IndexOf(T item, int index)
		{
			if (index > this._size)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return Array.IndexOf<T>(this._items, item, index, this._size - index);
		}
		public int IndexOf(T item, int index, int count)
		{
			if (index > this._size)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if ((count < 0) || (index > (this._size - count)))
			{
				throw new ArgumentOutOfRangeException("count or (index, count)");
			}
			return Array.IndexOf<T>(this._items, item, index, count);
		}
		public void Insert(int index, T item)
		{
			if (index > this._size)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (this.IsOkToAdd(item))
			{
				if (this._size == this._items.Length)
				{
					this.EnsureCapacity(this._size + 1);
				}
				if (index < this._size)
				{
					Array.Copy(this._items, index, this._items, index + 1, this._size - index);
				}
				this._items[index] = item;
				this._size++;
				this._version++;
				OnItemAdded(item);
			}
		}
		public void InsertRange(int index, IEnumerable<T> collection)
		{
			if (collection == null)
			{
				throw new ArgumentNullException("collection");
			}
			if (index > this._size)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (this.IsOkToAdd(collection))
			{
				ICollection<T> is2 = collection as ICollection<T>;
				if (is2 != null)
				{
					int count = is2.Count;
					if (count > 0)
					{
						this.EnsureCapacity(this._size + count);
						if (index < this._size)
						{
							Array.Copy(this._items, index, this._items, index + count, this._size - index);
						}
						if (this == is2)
						{
							Array.Copy(this._items, 0, this._items, index, index);
							Array.Copy(this._items, (int)(index + count), this._items, (int)(index * 2), (int)(this._size - index));
						}
						else
						{
							T[] array = new T[count];
							is2.CopyTo(array, 0);
							array.CopyTo(this._items, index);
						}
						this._size += count;
					}
				}
				else
				{
					using (IEnumerator<T> enumerator = collection.GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							this.Insert(index++, enumerator.Current);
						}
					}
				}
				this._version++;
				foreach (T t in collection)
					OnItemAdded(t);
			}
		}
		public int LastIndexOf(T item)
		{
			return this.LastIndexOf(item, this._size - 1, this._size);
		}
		public int LastIndexOf(T item, int index)
		{
			if (index >= this._size)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			return this.LastIndexOf(item, index, index + 1);
		}
		public int LastIndexOf(T item, int index, int count)
		{
			if (this._size == 0)
			{
				return -1;
			}
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException("index or count");
			}
			if ((index >= this._size) || (count > (index + 1)))
			{
				throw new ArgumentOutOfRangeException("index or (count, index)");
			}
			return Array.LastIndexOf<T>(this._items, item, index, count);
		}
		public virtual bool Remove(T item)
		{
			if (this.IsOkToRemove(item))
			{
				int index = this.IndexOf(item);
				if (index >= 0)
				{
					this.RemoveAt(index);
					return true;
				}
				return false;
			}
			return false;
		}
		public virtual int RemoveAll(Predicate<T> match)
		{
			if (match == null)
			{
				throw new ArgumentNullException("match");
			}
			int index = 0;
			while ((index < this._size) && !match(this._items[index]))
			{
				index++;
			}
			if (index >= this._size)
			{
				return 0;
			}
			int num2 = index + 1;
			while (num2 < this._size)
			{
				while ((num2 < this._size) && match(this._items[num2]))
				{
					OnItemRemoved(this._items[num2]);
					num2++;
				}
				if (num2 < this._size)
				{
					this._items[index++] = this._items[num2++];
				}
			}
			Array.Clear(this._items, index, this._size - index);
			int num3 = this._size - index;
			this._size = index;
			this._version++;
			return num3;
		}
		public virtual void RemoveAt(int index)
		{
			if (index >= this._size)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (this.IsOkToRemove(this[index]))
			{
				OnItemRemoved(this[index]);
				this._size--;
				if (index < this._size)
				{
					Array.Copy(this._items, index + 1, this._items, index, this._size - index);
				}
				this._items[this._size] = default(T);
				this._version++;
			}
		}
		public virtual void RemoveRange(int index, int count)
		{
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException("index or count");
			}
			if ((this._size - index) < count)
			{
				throw new ArgumentOutOfRangeException("index, count");
			}
			if (count > 0)
			{
				for (int i = index; i < index + count; ++i)
					OnItemRemoved(this[i]);

				this._size -= count;
				if (index < this._size)
				{
					Array.Copy(this._items, index + count, this._items, index, this._size - index);
				}
				Array.Clear(this._items, this._size, count);
				this._version++;
			}
		}
		public void Reverse()
		{
			this.Reverse(0, this.Count);
		}
		public void Reverse(int index, int count)
		{
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException("index or count");
			}
			if ((this._size - index) < count)
			{
				throw new ArgumentOutOfRangeException("index, count");
			}
			Array.Reverse(this._items, index, count);
			this._version++;
		}
		public void Sort()
		{
			this.Sort(0, this.Count, null);
		}
		public void Sort(IComparer<T> comparer)
		{
			this.Sort(0, this.Count, comparer);
		}
		public void Sort(Comparison<T> comparison)
		{
			if (comparison == null)
			{
				throw new ArgumentNullException("comparison");
			}
			if (this._size > 0)
			{
				IComparer<T> comparer = new FunctorComparer(comparison);
				Array.Sort<T>(this._items, 0, this._size, comparer);
			}
		}
		public void Sort(int index, int count, IComparer<T> comparer)
		{
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException("index or count");
			}
			if ((this._size - index) < count)
			{
				throw new ArgumentOutOfRangeException("index, count");
			}
			Array.Sort<T>(this._items, index, count, comparer);
			this._version++;
		}
		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			return new Enumerator((VList<T>)this);
		}
		void ICollection.CopyTo(Array array, int arrayIndex)
		{
			if ((array != null) && (array.Rank != 1))
			{
				throw new ArgumentException("array");
			}
			try
			{
				Array.Copy(this._items, 0, array, arrayIndex, this._size);
			}
			catch (ArrayTypeMismatchException)
			{
				throw new ArgumentException("array");
			}
		}
		IEnumerator IEnumerable.GetEnumerator()
		{
			return new Enumerator(this);
		}
		int IList.Add(object item)
		{
			VList<T>.VerifyValueType(item);
			this.Add((T)item);
			return (this.Count - 1);
		}
		bool IList.Contains(object item)
		{
			return (VList<T>.IsCompatibleObject(item) && this.Contains((T)item));
		}
		int IList.IndexOf(object item)
		{
			if (VList<T>.IsCompatibleObject(item))
			{
				return this.IndexOf((T)item);
			}
			return -1;
		}
		void IList.Insert(int index, object item)
		{
			VList<T>.VerifyValueType(item);
			this.Insert(index, (T)item);
		}
		void IList.Remove(object item)
		{
			if (VList<T>.IsCompatibleObject(item))
			{
				this.Remove((T)item);
			}
		}
		public T[] ToArray()
		{
			T[] destinationArray = new T[this._size];
			Array.Copy(this._items, 0, destinationArray, 0, this._size);
			return destinationArray;
		}
		public void TrimExcess()
		{
			int num = (int)(this._items.Length * 0.9);
			if (this._size < num)
			{
				this.Capacity = this._size;
			}
		}
		public bool TrueForAll(Predicate<T> match)
		{
			if (match == null)
			{
				throw new ArgumentNullException("match");
			}
			for (int i = 0; i < this._size; i++)
			{
				if (!match(this._items[i]))
				{
					return false;
				}
			}
			return true;
		}
		// Properties
		public int Capacity
		{
			get
			{
				return this._items.Length;
			}
			set
			{
				if (value != this._items.Length)
				{
					if (value < this._size)
					{
						throw new ArgumentOutOfRangeException("value");
					}
					if (value > 0)
					{
						T[] destinationArray = new T[value];
						if (this._size > 0)
						{
							Array.Copy(this._items, 0, destinationArray, 0, this._size);
						}
						this._items = destinationArray;
					}
					else
					{
						this._items = VList<T>._emptyArray;
					}
				}
			}
		}
		public int Count
		{
			get
			{
				return this._size;
			}
		}
		public T this[int index]
		{
			get
			{
				if (index >= this._size)
				{
					throw new ArgumentOutOfRangeException("index");
				}
				return this._items[index];
			}
			set
			{
				if (index >= this._size)
				{
					throw new ArgumentOutOfRangeException("index");
				}
				this._items[index] = value;
				this._version++;
			}
		}
		bool ICollection<T>.IsReadOnly
		{
			get
			{
				return false;
			}
		}
		bool ICollection.IsSynchronized
		{
			get
			{
				return false;
			}
		}
		object ICollection.SyncRoot
		{
			get
			{
				if (this._syncRoot == null)
				{
					Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
				}
				return this._syncRoot;
			}
		}
		bool IList.IsFixedSize
		{
			get
			{
				return false;
			}
		}
		bool IList.IsReadOnly
		{
			get
			{
				return false;
			}
		}
		object IList.this[int index]
		{
			get
			{
				return this[index];
			}
			set
			{
				VList<T>.VerifyValueType(value);
				this[index] = (T)value;
			}
		}
		// Nested Types
		[Serializable, StructLayout(LayoutKind.Sequential)]
		public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator
		{
			private VList<T> list;
			private int index;
			private int version;
			private T current;
			internal Enumerator(VList<T> list)
			{
				this.list = list;
				this.index = 0;
				this.version = list._version;
				this.current = default(T);
			}
			public void Dispose()
			{
			}
			public bool MoveNext()
			{
				VList<T> list = this.list;
				if ((this.version == list._version) && (this.index < list._size))
				{
					this.current = list._items[this.index];
					this.index++;
					return true;
				}
				return this.MoveNextRare();
			}
			private bool MoveNextRare()
			{
				if (this.version != this.list._version)
				{
					throw new InvalidOperationException("EnumFailedVersion");
				}
				this.index = this.list._size + 1;
				this.current = default(T);
				return false;
			}
			public T Current
			{
				get
				{
					return this.current;
				}
			}
			object IEnumerator.Current
			{
				get
				{
					if ((this.index == 0) || (this.index == (this.list._size + 1)))
					{
						throw new InvalidOperationException("EnumOpCantHappen");
					}
					return this.Current;
				}
			}
			void IEnumerator.Reset()
			{
				if (this.version != this.list._version)
				{
					throw new ArgumentOutOfRangeException("EnumFailedVersion");
				}
				this.index = 0;
				this.current = default(T);
			}
		}
		#endregion
		#endregion
		#region INTERNAL
		#region CONST/STATIC
		private static T[] _emptyArray;
		static VList()
		{
			VList<T>._emptyArray = new T[0];
		}
		#endregion
		#region VARS
		private const int _defaultCapacity = 4;
		private T[] _items;
		private int _size;
		[NonSerialized]
		private object _syncRoot;
		private int _version;
		#endregion
		#region METHODS
		private void EnsureCapacity(int min)
		{
			if (this._items.Length < min)
			{
				int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
				if (num < min)
				{
					num = min;
				}
				this.Capacity = num;
			}
		}
		private static bool IsCompatibleObject(object value)
		{
			if (!(value is T) && ((value != null) || typeof(T).IsValueType))
			{
				return false;
			}
			return true;
		}
		private static void VerifyValueType(object value)
		{
			if (!VList<T>.IsCompatibleObject(value))
			{
				throw new ArgumentException("value");
			}
		}
		protected virtual bool IsOkToAdd(T item)
		{
			return true;
		}
		protected virtual bool IsOkToAdd(IEnumerable<T> collection)
		{
			return true;
		}
		protected virtual bool IsOkToRemove(T item)
		{
			return true;
		}
		/// <summary>
		/// Called when an item is added to the collection.
		/// </summary>
		/// <param name="item"></param>
		protected virtual void OnItemAdded(T item)
		{
		}
		/// <summary>
		/// Called when an item is removed from the collection.
		/// </summary>
		/// <param name="item"></param>
		protected virtual void OnItemRemoved(T item)
		{
		}
		#endregion
		#endregion
		class FunctorComparer : IComparer<T>
		{
			Comparison<T> _comparison;
			internal FunctorComparer(Comparison<T> comparison)
			{
				this._comparison = comparison;
			}
			#region IComparer<T> Members
			public int Compare(T x, T y)
			{
				return this._comparison(x, y);
			}
			#endregion
		}
	}
}
